package career_handler

import (
	er "errors"
	"fmt"
	"io"
	"mime/multipart"
	"net/http"
	"path"
	"peilian-api/app/global/bind"
	"peilian-api/app/global/common"
	"peilian-api/app/global/databases/tables"
	"peilian-api/app/global/errors"
	"peilian-api/app/global/log"
	"peilian-api/app/global/variable"
	"peilian-api/app/model"
	"peilian-api/app/services/label_service"
	"peilian-api/app/services/tiku_service"
	"peilian-api/utils/format"
	"peilian-api/utils/function"
	"peilian-api/utils/sdk"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

const DefaultCareerPhoto = "peilian/static/career_photos/2023-04-18/d8a200c9bd4b2e10c8cf82f370a7f04d.png"

func CareerPhotoHandler(f *multipart.FileHeader) (string, error) {
	if f == nil {
		return DefaultCareerPhoto, fmt.Errorf("没有图片文件")
	}
	fileExt := strings.ToLower(path.Ext(f.Filename))
	fileName := function.CreateMD5(fmt.Sprintf("%s%s", f.Filename, time.Now().String())) + fileExt
	filePath := common.CareerPhotoPath + fileName
	savePath := variable.Config.UfsInfo.BucketPrefix + filePath
	fmt.Println("CareerPhotoHandler -->", savePath)
	f2, err := f.Open()
	if err != nil {
		return "", fmt.Errorf("上传异常, " + err.Error())
	}
	fileData, err := io.ReadAll(f2)
	if err != nil {
		return "", fmt.Errorf("上传IO异常, " + err.Error())
	}
	err = sdk.IOput(fileData, savePath, "")
	if err != nil {
		return "", fmt.Errorf("上传IO失败, " + err.Error())
	}
	fmt.Println("CareerPhotoHandler -->", savePath)
	return savePath, nil
}

func CustomCareerList(c *gin.Context) {
	agentId, _ := c.Get("aid")
	careerId := c.Param("careerId")
	var (
		t = true
		f = false
	)
	inList := func(sL []string, s string) *bool {
		for _, ss := range sL {
			if ss == s {
				return &f
			}
		}
		return &t
	}
	if len(careerId) != 0 {
		var career tables.Career
		if err := variable.DB.MySQL.Where("career_type = 'interview' and is_available <> ? and agent_id in (0, ?)", 2, agentId).Preload("Profession").
			First(&career, careerId).Error; err != nil {
			format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
			return
		}
		career.AdminCareerShow = inList(strings.Split(career.NotShowAgentIds, ","), fmt.Sprintf("%v", agentId))
		format.NewResponseJson(c).SuccessObj(&career)
		return
	}
	var career []*tables.Career
	if err := variable.DB.MySQL.Where("career_type = 'interview' and is_available <> ? and agent_id in (0, ?)", 2, agentId).Preload("Profession").
		Order("order_id asc").Find(&career).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	for i, car := range career {
		career[i].AdminCareerShow = inList(strings.Split(car.NotShowAgentIds, ","), fmt.Sprintf("%v", agentId))
	}

	format.NewResponseJson(c).SuccessDataList(len(career), career)
}

func CustomCareerCreate(c *gin.Context) {
	var career tables.Career
	if err := c.ShouldBind(&career); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	photo, err := CareerPhotoHandler(career.CareerPhotoStream)
	if err != nil {
		if len(photo) == 0 {
			format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
			return
		} else {
			isDefault := true
			career.PhotoIsDefault = &isDefault
		}
	}
	career.CareerPhoto = variable.Config.UfsInfo.UfsUrl + photo
	career.SetCustomDefault()
	rid, _ := c.Get("rid")
	if rid.(uint) == 2 { // 2-表示超级管理员在数据库中的id
		career.AgentId = 0
	} else {
		agentId, exist := c.Get("aid")
		if !exist {
			format.NewResponseJson(c).Err(http.StatusBadRequest, "agent_id未解析到")
			return
		}
		career.AgentId = agentId.(uint)
	}
	if career.ProfessionId != nil {
		p, err := tables.GetProfessionById(*career.ProfessionId)
		if err != nil || p.ID == 0 {
			format.NewResponseJson(c).Err(http.StatusBadRequest, "Profession 未获取到")
			return
		}
		career.Profession = p
	}

	if err := career.SaveValidate(); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	var n int64
	variable.DB.MySQL.Model(&tables.Career{}).Where("name=?", career.Name).Count(&n)
	if n > 0 {
		format.NewResponseJson(c).Err(http.StatusBadRequest, "岗位名称已经存在")
		return
	}
	db := tables.CustomLabel{}
	label := db.GetLabelByName(career.Name)
	if label != nil && label.ID != 0 {
		career.ReportType = "web"
	}

	if err := variable.DB.MySQL.Create(&career).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusInternalServerError, err.Error())
		return
	}
	// 生成对应的标签
	if label == nil || label.ID == 0 {
		// 生成对应的标签
		_, err = label_service.CreateLabel(c, label_service.CreateLabelReq{JobName: career.Name})
		if err != nil {
			log.Logger.ErrorF(c, fmt.Sprintf("CreateLabel error :%+v", err))
		}
	}

	format.NewResponseJson(c).SuccessObj(career)
}

func CustomCareerUpdate(c *gin.Context) {
	var careerReq tables.Career
	agentId, exist := c.Get("aid")
	if !exist {
		format.NewResponseJson(c).Err(http.StatusBadRequest, "agent_id未解析到")
		return
	}
	if err := c.ShouldBind(&careerReq); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	photo, err := CareerPhotoHandler(careerReq.CareerPhotoStream)
	fmt.Printf("CareerPhotoHandler error -->%+v\n", err)
	if err == nil {
		careerReq.CareerPhoto = variable.Config.UfsInfo.UfsUrl + photo
	}
	if err := careerReq.UpdateValidate(); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	careerId := c.Param("careerId")
	if careerReq.IsRelease != nil && *careerReq.IsRelease {
		var hasReleased bool
		variable.DB.MySQL.Model(&tables.Career{}).Select("IsRelease").Where("id=?", careerId).Scan(&hasReleased)
		if hasReleased {
			format.NewResponseJson(c).Err(http.StatusBadRequest, "该岗位已经发布")
			return
		}
		var interviewQuesCount int64
		variable.DB.MySQL.Model(&tables.CustomCareer{}).Where("career_id=?", careerId).Count(&interviewQuesCount)
		if interviewQuesCount <= 0 {
			format.NewResponseJson(c).Err(http.StatusBadRequest, "请绑定面试题目")
			return
		}
	}
	if careerReq.AdminCareerShow != nil {
		var oldAgentIds string
		variable.DB.MySQL.Model(&tables.Career{}).Select("NotShowAgentIds").Where("id=?", careerId).Scan(&oldAgentIds)
		var agentMap = make(map[string]string)
		for _, ag := range strings.Split(oldAgentIds, ",") {
			agentMap[ag] = ag
		}
		agentIdStr := agentId.(uint)
		if *careerReq.AdminCareerShow {
			delete(agentMap, fmt.Sprintf("%d", agentIdStr))
		} else {
			agentMap[fmt.Sprintf("%d", agentIdStr)] = "a"
		}
		var agentIds []string
		for k, _ := range agentMap {
			if k != "" {
				agentIds = append(agentIds, k)
			}
		}
		if len(agentIds) == 0 {
			agentIds = append(agentIds, ",")
		}
		careerReq.NotShowAgentIds = strings.Join(agentIds, ",")

	}
	if careerReq.ProfessionId != nil {
		p, err := tables.GetProfessionById(*careerReq.ProfessionId)
		if err != nil || p.ID == 0 {
			format.NewResponseJson(c).Err(http.StatusBadRequest, "Profession 未获取到")
			return
		}
	}
	if careerReq.Name != "" {
		db := tables.CustomLabel{}
		label := db.GetLabelByName(careerReq.Name)
		if label != nil && label.ID != 0 {
			careerReq.ReportType = "web"
		} else {
			// 生成对应的标签
			_, err = label_service.CreateLabel(c, label_service.CreateLabelReq{JobName: careerReq.Name})
			if err != nil {
				log.Logger.ErrorF(c, fmt.Sprintf("CreateLabel error :%+v", err))
			}
			careerReq.ReportType = "custom"
		}
	}

	if err := variable.DB.MySQL.Model(&tables.Career{}).Where("id=?", careerId).Updates(&careerReq).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	var career tables.Career
	if err := variable.DB.MySQL.Preload("Profession").First(&career, careerId).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	format.NewResponseJson(c).SuccessObj(&career)
}

func CustomCareerDelete(c *gin.Context) {
	careerId := c.Param("careerId")
	if err := variable.DB.MySQL.Transaction(func(tx *gorm.DB) error {
		if err := variable.DB.MySQL.Model(&tables.Career{}).Where("id=?", careerId).
			Update("name", gorm.Expr("concat(name,?)", time.Now().Format("20060102030405"))).Error; err != nil {
			return err
		}
		if err := variable.DB.MySQL.Delete(&tables.Career{}, careerId).Error; err != nil {
			return err
		}
		if err := variable.DB.MySQL.Delete(&tables.CustomCareer{}, "career_id=?", careerId).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}

	format.NewResponseJson(c).SuccessObj(struct{}{})
}

func CareerQuestionLink(c *gin.Context) {
	questionIds := make([][]uint, 0)
	if err := c.ShouldBindJSON(&questionIds); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	customCareerId := c.Param("careerId")
	var career tables.Career
	if err := variable.DB.MySQL.Select("ID", "Type", "QuestionNum").First(&career, customCareerId).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	if career.Type != "自定义" {
		format.NewResponseJson(c).Error(http.StatusBadRequest, "该职位不是自定义职位,无法修改")
		return
	}
	if len(questionIds) != career.QuestionNum {
		format.NewResponseJson(c).Err(http.StatusBadRequest, "题目数量与设置的不一致")
		return
	}

	if err := variable.DB.MySQL.Transaction(func(tx *gorm.DB) error {
		linkLi := make([]*tables.CustomCareer, 0)
		if err := variable.DB.MySQL.Delete(&tables.CustomCareer{}, "career_id=?", customCareerId).Error; err != nil {
			return err
		}
		id, _ := strconv.Atoi(customCareerId)
		for i, questionLi := range questionIds {
			var qs int64
			variable.DB.MySQL.Model(&tables.Question{}).Where("id in (?)", questionLi).Count(&qs)
			if len(questionLi) < 1 || qs < 1 {
				return er.New(fmt.Sprintf("第[%d]道题的关联题目数量不够", i+1))
			}
			for _, q := range questionLi {
				link := &tables.CustomCareer{
					CareerID:   uint(id),
					Tag:        i + 1,
					QuestionID: q,
				}
				linkLi = append(linkLi, link)
			}
		}
		if err := variable.DB.MySQL.Create(&linkLi).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	format.NewResponseJson(c).SuccessObj(struct{}{})
}

type QuestionBindParam struct {
	CareerId uint `uri:"careerId"`
	Tag      int  `uri:"question_order_tag"`
}

func CustomCareerGetBindQuestions(c *gin.Context) {
	var questionBindReq QuestionBindParam
	if err := c.ShouldBindUri(&questionBindReq); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	questionIdSubQuery := variable.DB.MySQL.Model(&tables.CustomCareer{}).
		Where("career_id=? and tag=?", questionBindReq.CareerId, questionBindReq.Tag).Select("QuestionID")
	questions := make([]*tables.QuestionResp, 0)
	if err := variable.DB.MySQL.Select("Text", "ID", "CareerID", "AnsAnalysis", "Level", "VideoStatus", "Source").
		Model(&tables.Question{}).Where("id in (?)", questionIdSubQuery).
		Scan(&questions).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusInternalServerError, err.Error())
		return
	}
	for _, q := range questions {
		q.SkillTagIds = make([]*tables.Criteria, 0)
		if err := variable.DB.MySQL.Model(&q.Question).
			Association("SkillTags").Find(&q.SkillTagIds); err != nil {
			continue
		}
	}
	format.NewResponseJson(c).SuccessDataList(len(questions), questions)
}

func CustomCareerChangeBindQuestions(c *gin.Context) {
	var questionBindReq QuestionBindParam
	if err := c.ShouldBindUri(&questionBindReq); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	questionIds := make([]uint, 0)
	if err := c.ShouldBindJSON(&questionIds); err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	if len(questionIds) <= 0 {
		format.NewResponseJson(c).Err(http.StatusBadRequest, "请指定题目集合")
		return
	}
	var career tables.Career
	if err := variable.DB.MySQL.Select("ID", "Type", "QuestionNum").First(&career, questionBindReq.CareerId).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusBadRequest, err.Error())
		return
	}
	if career.Type != "自定义" {
		format.NewResponseJson(c).Error(http.StatusBadRequest, "该职位不是自定义职位,无法修改")
		return
	}
	if err := variable.DB.MySQL.Transaction(func(tx *gorm.DB) error {
		linkLi := make([]*tables.CustomCareer, 0)
		if err := variable.DB.MySQL.Where("career_id=? and tag=?", questionBindReq.CareerId, questionBindReq.Tag).
			Delete(&tables.CustomCareer{}).Error; err != nil {
			return err
		}
		var qs int64
		variable.DB.MySQL.Model(&tables.Question{}).Where("id in (?)", questionIds).Count(&qs)
		if qs < 1 {
			return er.New(fmt.Sprintf("第[%d]道题的关联题目数量不够", questionBindReq.Tag))
		}
		for _, q := range questionIds {
			link := &tables.CustomCareer{
				CareerID:   questionBindReq.CareerId,
				Tag:        questionBindReq.Tag,
				QuestionID: q,
			}
			linkLi = append(linkLi, link)
		}
		if err := variable.DB.MySQL.Create(&linkLi).Error; err != nil {
			return err
		}
		return nil
	}); err != nil {
		format.NewResponseJson(c).Err(http.StatusInternalServerError, err.Error())
		return
	}
	questions := make([]*tables.QuestionResp, 0)
	if err := variable.DB.MySQL.Select("Text", "ID", "CareerID", "AnsAnalysis", "Level", "VideoStatus", "Source").
		Model(&tables.Question{}).Where("id in (?)", questionIds).
		Scan(&questions).Error; err != nil {
		format.NewResponseJson(c).Err(http.StatusInternalServerError, err.Error())
		return
	}
	for _, q := range questions {
		q.SkillTagIds = make([]*tables.Criteria, 0)
		if err := variable.DB.MySQL.Model(&q.Question).
			Association("SkillTags").Find(&q.SkillTagIds); err != nil {
			continue
		}
	}
	format.NewResponseJson(c).SuccessDataList(len(questions), &questions)
}

/**
 * 接收回调消息
 *  post 请求
 * 参数：
 * {
 *  	"type":"youshi_video_finish",
 *   	"topic":"topic_youshi_local",
 *  	"message":"{\"id\":1,\"text\":\"这是个问题\",\"video\":\"http://xxxxx.mp3\",\"pc_video\":\"http://xxxx.mp3\"}"
 *	}
 */
func GenerateVideoFinish(c *gin.Context) {
	var gvfr model.GenerateVideoFinishReq
	if err := bind.ShouldBinding(c, &gvfr); err != nil {
		format.NewResponseJson(c).ErrObj(errors.PublicErrorCode, errors.ParamBindError)
		return
	}
	err := new(tiku_service.TikuService).GenerationVideoFinish(c, gvfr)
	if err != nil {
		log.Logger.InfoMsgF(c, "general video is error, "+err.Error())
		format.NewResponseJson(c).SuccessObj(struct{}{})
		return
	}
	format.NewResponseJson(c).SuccessObj(struct{}{})
}
